package sk.lukaskrupa.guess.the.color.ui;

import static sk.lukaskrupa.guess.the.color.core.ApplicationConstants.BOARD_KEY;
import static sk.lukaskrupa.guess.the.color.core.ApplicationConstants.MAX_GUESSES;
import sk.lukaskrupa.guess.the.color.core.ApplicationConstants;
import sk.lukaskrupa.guess.the.color.core.Board;
import sk.lukaskrupa.guess.the.color.core.GameVariantSpecificActions;
import sk.lukaskrupa.guess.the.color.listeners.ColorPickerButtonListener;
import sk.lukaskrupa.guess.the.color.listeners.CommonButtonListener;
import sk.lukaskrupa.guess.the.color.listeners.GameButtonListener;
import sk.lukaskrupa.guess.the.color.logging.Logging;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TableRow;
import android.widget.Toast;

/**
 * Activity where main game is done.
 * 
 * @author Lukas Krupa (lukas0krupa@gmail.com)
 * 
 */
public class Game extends Activity implements OnClickListener {

	// Logging
	private static Logging logger = Logging.getLog(Game.class);

	private View mainView;
	private ColorPicker colorPicker;
	private Board board;
	private GameVariantSpecificActions gameVariants;

	private CommonButtonListener commonButtonListener;
	private ColorPickerButtonListener colorPickerButtonListener;
	private GameButtonListener gameButtonListener;

	private TableRow[] rows;

	public static ImageButton lastClicked;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		logger.info("onCreate", "Creating game.");

		// Load game settings
		this.gameVariants = new GameVariantSpecificActions(getSharedPreferences(getResources().getString(R.string.applicationData),
				MODE_PRIVATE));

		// Color picker listener
		logger.debug("onCreate", "Setting common button listener.");
		this.colorPickerButtonListener = new ColorPickerButtonListener(this, this.gameVariants);

		// Color picker
		logger.debug("onStart", "Color picker setup.");
		this.colorPicker = new ColorPicker(this, this.colorPickerButtonListener);

		// Listeners
		logger.debug("onCreate", "Setting common button listener.");
		this.commonButtonListener = new CommonButtonListener(this.colorPicker);
		this.gameButtonListener = new GameButtonListener(this);

		// Board
		this.board = new Board();
		if (savedInstanceState != null && savedInstanceState.containsKey(BOARD_KEY)) {
			this.board = (Board) savedInstanceState.get(BOARD_KEY);
		} else {
			this.board.initBoard(this.gameVariants.generateRandomColors());
			this.gameVariants.modifyColorPickerAccordingToDifficulty(this.colorPicker);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onStart() {
		super.onStart();

		logger.info("onStart", "Starting game.");
		setContentView(R.layout.game);

		// Setting View settings
		logger.debug("onStart", "Persisting reference to MainView and setting it.");
		this.mainView = findViewById(R.id.board);
		this.mainView.setBackgroundColor(Color.DKGRAY);

		// Getting all rows
		logger.debug("onStart", "Saving reference for rows.");
		this.rows = new TableRow[10];
		this.rows[0] = (TableRow) findViewById(R.id.guessedColor1);
		this.rows[1] = (TableRow) findViewById(R.id.guessedColor2);
		this.rows[2] = (TableRow) findViewById(R.id.guessedColor3);
		this.rows[3] = (TableRow) findViewById(R.id.guessedColor4);
		this.rows[4] = (TableRow) findViewById(R.id.guessedColor5);
		this.rows[5] = (TableRow) findViewById(R.id.guessedColor6);
		this.rows[6] = (TableRow) findViewById(R.id.guessedColor7);
		this.rows[7] = (TableRow) findViewById(R.id.guessedColor8);
		this.rows[8] = (TableRow) findViewById(R.id.guessedColor9);
		this.rows[9] = (TableRow) findViewById(R.id.guessedColor10);

		// Setting other listeners
		findViewById(R.id.sendGame).setOnClickListener(this.gameButtonListener);
		findViewById(R.id.giveUpGame).setOnClickListener(this.gameButtonListener);
		findViewById(R.id.backToMenuGame).setOnClickListener(this.gameButtonListener);

		// Setting to invisible
		logger.debug("debug", "Hidding all rows (except hidden color row)");
		int rowIndex = 0;
		for (TableRow row : this.rows) {

			// Setting invisibility
			row.setVisibility(View.INVISIBLE);

			// Other settings
			for (int columIndex = 1; columIndex <= MAX_GUESSES; columIndex++) {

				ImageButton guessButton = (ImageButton) row.getChildAt(columIndex - 1);
				ImageButton resultButton = (ImageButton) row.getChildAt(columIndex + 5);

				// Setting Button listener
				guessButton.setOnClickListener(this.commonButtonListener);
				// Setting Image
				guessButton.setImageDrawable(getResources().getDrawable(this.board.getButtonStatusAt(rowIndex + 1, columIndex, true)));
				resultButton.setImageDrawable(getResources().getDrawable(this.board.getButtonStatusAt(rowIndex + 1, columIndex, false)));
			}
			rowIndex++;
		}

		// Showing only those that was used
		logger.debug("onStart", "Unhidding rows till last visible.");
		for (rowIndex = 0; rowIndex < this.board.getGuessingRow(); rowIndex++) {
			this.rows[rowIndex].setVisibility(View.VISIBLE);
		}

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);

		logger.debug("onSaveInstanceState", "Saving applicatino state.");
		outState.putSerializable(BOARD_KEY, this.board);
	}

	/**
	 * Shows results.
	 */
	public void showResults() {
		TableRow row = this.rows[this.board.getGuessingRow() - 1];

		for (int indexColumn = 1; indexColumn <= MAX_GUESSES; indexColumn++) {

			((ImageButton) row.getChildAt(indexColumn + 5)).setImageDrawable(getResources().getDrawable(
					this.board.getButtonStatusAt(this.board.getGuessingRow(), indexColumn, false)));
		}
	}

	/**
	 * Do initialization of Board.
	 */
	public void initBoard() {

		logger.info("initBoard", "Reseting game");
		this.board.initBoard(this.gameVariants.generateRandomColors());
		this.gameVariants.modifyColorPickerAccordingToDifficulty(this.colorPicker);

		// Setting HIDDEN row
		logger.debug("initBoard", "Setting HIDDEN row");
		TableRow hiddenRow = (TableRow) findViewById(R.id.hiddenRow);
		for (int columIndex = 1; columIndex <= MAX_GUESSES; columIndex++) {

			ImageButton button = (ImageButton) hiddenRow.getChildAt(columIndex - 1);
			button.setImageDrawable(getResources().getDrawable(R.drawable.hidden_color));
		}

		//
		logger.debug("initBoard", "Hidding all rows (except hidden color row and 1st guessing row)");
		int rowIndex = 0;
		for (TableRow row : this.rows) {
			rowIndex++;

			// Setting invisibility
			if (rowIndex > 1) {
				row.setVisibility(View.INVISIBLE);
			}

			// Other settings
			for (int columIndex = 1; columIndex <= MAX_GUESSES; columIndex++) {

				ImageButton guessButton = (ImageButton) row.getChildAt(columIndex - 1);
				ImageButton resultButton = (ImageButton) row.getChildAt(columIndex + 5);

				guessButton.setImageDrawable(getResources().getDrawable(this.board.getButtonStatusAt(rowIndex, columIndex, true)));
				resultButton.setImageDrawable(getResources().getDrawable(this.board.getButtonStatusAt(rowIndex, columIndex, false)));

				// Removing Tags (ID of drawable is there stored)
				guessButton.setTag(ApplicationConstants.DRAWABLE_ID, 0);

			}

			// Setting all buttons to click able again
			enableOrDisableButtons(row, true);

			this.colorPicker.enableButtons();
		}

	}

	/**
	 * Enables or disables children in row to be clicked.
	 * 
	 * @param row
	 *            to be enabled or disabled
	 * @param changeTo
	 *            what to do with
	 */
	private void enableOrDisableButtons(TableRow row, boolean changeTo) {
		for (int child = 0; child < row.getChildCount(); child++) {
			row.getChildAt(child).setClickable(changeTo);
		}
	}

	/**
	 * Unhides guessing row.
	 */
	public void unhideGuessingRow() {

		TableRow row = this.rows[this.board.getGuessingRow() - 1];

		for (int indexColumn = 1; indexColumn <= MAX_GUESSES; indexColumn++) {

			ImageButton guessButton = (ImageButton) row.getChildAt(indexColumn);
			ImageButton resultButton = (ImageButton) row.getChildAt(indexColumn + 5);

			guessButton.setImageDrawable(getResources().getDrawable(
					this.board.getButtonStatusAt(this.board.getGuessingRow(), indexColumn, true)));
			resultButton.setImageDrawable(getResources().getDrawable(
					this.board.getButtonStatusAt(this.board.getGuessingRow(), indexColumn, false)));
		}

		row.setVisibility(View.VISIBLE);
		enableOrDisableButtons(this.rows[this.board.getGuessingRow() - 2], false);

	}

	/**
	 * Close shown color picker.
	 */
	public void closeColorPicker() {
		this.colorPicker.closeColorPicker();
	}

	/**
	 * If guessed color are equal as hidden.
	 */
	public void isWinner() {
		defaultAlertDialog("Game results", "Congratulation, you win this game !");
	}

	/**
	 * If user run out of tries.
	 */
	public void isLooser() {
		defaultAlertDialog("Game results", "I am sorry, you loose this game !");
	}

	/**
	 * Default action in both case, winner or loser.
	 * 
	 * @param title
	 *            to use
	 * @param message
	 *            to use
	 */
	private void defaultAlertDialog(String title, String message) {
		showHiddenColors();

		AlertDialog alertDialog = new AlertDialog.Builder(this).create();
		alertDialog.setTitle(title);
		alertDialog.setMessage(message);
		alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "Reset", this);
		alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Back to menu", this);
		alertDialog.show();
	}

	/**
	 * Show hidden colors.
	 */
	private void showHiddenColors() {

		TableRow hiddenRow = (TableRow) findViewById(R.id.hiddenRow);

		for (int indexColumn = 1; indexColumn <= MAX_GUESSES; indexColumn++) {

			((ImageButton) hiddenRow.getChildAt(indexColumn - 1)).setImageDrawable(getResources().getDrawable(
					this.board.getHiddenRow().get(indexColumn).getDrawableId()));
		}

	}

	/**
	 * Process input and do necessary actions.
	 */
	public void validateInput() {

		if (this.gameVariants.guessMatch(this.board)) {

			this.isWinner();
		} else if (this.getBoard().getGuessingRow() < 10) {

			this.showResults();
			this.getBoard().increaseGuessingRow();
			this.unhideGuessingRow();
			this.colorPicker.enableButtons();
		} else {
			this.isLooser();
		}

	}

	/**
	 * Checks if input is completed and complete.
	 * 
	 * @return true, if validation could be run
	 */
	public boolean isComplete() {

		boolean isOk = true;

		// Checking if all guesses used
		isOk &= this.getBoard().hasAllGuesses();

		if (!isOk) {
			Toast errorMessage = Toast.makeText(getApplicationContext(), "Please use all inputs", Toast.LENGTH_LONG);
			errorMessage.setGravity(Gravity.CENTER, 0, 0);

			errorMessage.show();
		}

		return isOk;
	}

	/**
	 * Giving up with game, showing hidden colors, and asking for return to game
	 * or reseting game.
	 */
	public void giveUp() {
		this.isLooser();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onClick(DialogInterface dialog, int which) {
		if (DialogInterface.BUTTON_POSITIVE == which) {
			logger.debug("onClick", "Possitive buton clicke [RESET].");
			this.initBoard();
		} else {
			logger.debug("onClick", "Negative buton clicke [BACK TO MENU].");
			this.finish();
		}
	}

	// GETTERS.

	/**
	 * Gets value colorPickerButtonListener.
	 * 
	 * @return the colorPickerButtonListener
	 */
	public ColorPickerButtonListener getColorPickerButtonListener() {
		return this.colorPickerButtonListener;
	}

	/**
	 * Sets colorPickerButtonListener.
	 * 
	 * @param colorPickerButtonListener
	 *            the colorPickerButtonListener to set
	 */
	public void setColorPickerButtonListener(ColorPickerButtonListener colorPickerButtonListener) {
		this.colorPickerButtonListener = colorPickerButtonListener;
	}

	/**
	 * Gets value rows.
	 * 
	 * @return the rows
	 */
	public TableRow[] getRows() {
		return this.rows;
	}

	/**
	 * Gets value mainView.
	 * 
	 * @return the mainView
	 */
	public View getMainView() {
		return this.mainView;
	}

	/**
	 * Gets value board.
	 * 
	 * @return the board
	 */
	public Board getBoard() {
		return this.board;
	}

	/**
	 * Sets board.
	 * 
	 * @param board
	 *            the board to set
	 */
	public void setBoard(Board board) {
		this.board = board;
	}

}
